#include "Regexp.h"

using namespace regexp;

Regexp::Regexp()
{
	_operator = ONE;
	terminals = "";
    left = NULL;
    right = NULL;
}

Regexp::Regexp(string p)
{
	_operator = ONE;
    terminals = p;
    left = NULL;
    right = NULL;
}

Regexp::~Regexp()
{
	delete left;
	delete right;
}

Regexp *Regexp::plus()
{
    Regexp *result = new Regexp();
	result->_operator = PLUS;
    result->left = this;
    return result;
}

Regexp *Regexp::star()
{
    Regexp *result = new Regexp();
	result->_operator = STAR;
    result->left = this;
    return result;
}

Regexp *Regexp::or(Regexp *e2)
{
    Regexp *result = new Regexp();
	result->_operator = OR;
    result->left = this;
    result->right = e2;
    return result;
}

Regexp *Regexp::dot(Regexp *e2)
{
    Regexp *result = new Regexp();
	result->_operator = DOT;
    result->left = this;
	result->right = e2;
    return result;
}

int Regexp::compareString(string s1, string s2)
{
	if (s1.length() == s2.length())
	{
		return s1.compare(s2);
	}
    else
	{
		return (int)s1.length() - (int)s2.length();
	}
}

bool Regexp::operator== (const Regexp &other) const
{
	bool result = (_operator == other._operator && terminals == other.terminals);
	return result;
}

set <string>Regexp::getLanguage(int maxSteps)
{
	set<string> *emptyLanguage = new set<string>();
    set<string> *languageResult = new set<string>();
	
	set<string> languageLeft, languageRight;
	
	if (maxSteps < 1)
	{
		return *emptyLanguage;
	} 
        switch (_operator) 
		{
            case ONE:
				{languageResult->insert(terminals);}

            case OR:
                languageLeft = left == NULL ? *emptyLanguage : left->getLanguage(maxSteps - 1);
				languageRight = right == NULL ? *emptyLanguage : right->getLanguage(maxSteps - 1);
				languageResult->insert(languageLeft.begin(), languageLeft.end());
				languageResult->insert(languageRight.begin(), languageRight.end());
				break;
                
            case DOT:
                languageLeft = left == NULL ? *emptyLanguage : left->getLanguage(maxSteps - 1);
                languageRight = right == NULL ? *emptyLanguage : right->getLanguage(maxSteps - 1);
				
				for (set<string>::iterator it = languageLeft.begin(); it != languageLeft.end(); it++) {
					string a = *it;
					for(set<string>::iterator it = languageRight.begin(); it != languageRight.end(); it++)
					{
						string b = *it;
						languageResult->insert(a + b);
					}
				}
				break;
			case STAR:

			case PLUS:
                languageLeft = left == NULL ? *emptyLanguage : left->getLanguage(maxSteps - 1);
				languageResult->insert(languageLeft.begin(), languageLeft.end());
                for (int i = 1; i < maxSteps; i++)
                {   
					set<string> languageTemp = *languageResult;
					for (set<string>::iterator it = languageLeft.begin(); it != languageLeft.end(); it++) 
					{
						string a = *it;
						for(set<string>::iterator it = languageTemp.begin(); it != languageTemp.end(); it++)
						{
							string b = *it;
							languageResult->insert(a + b);
						}	
					}
				}
				if (this->_operator  == STAR)
                {
					languageResult->insert("");
				}
                break;
			case START:
				languageLeft = left == NULL ? *emptyLanguage : *languageResult;
				languageResult->insert(languageLeft.begin(), languageLeft.end());	
				break;
                               
            default:
                cout << "getLanguage is nog niet gedefinieerd voor de operator: " + this->_operator <<endl;
                break;
		} 
        return *languageResult;
}

ostream& operator <<(ostream& os, const set<string> &exp) {
	copy(exp.begin(), exp.end(), ostream_iterator<const string>(os, " | "));
	return os;
}